#include "symbolTable/Expression.h"
#include "type/Type.h"
#include <memory>

UniAST::RightValue::RightValue(std::shared_ptr<UniAST::Type> exprtype,
                               mlir::Value mlirValue)
    : mlirValue(mlirValue), exprtype(exprtype)
{
}

void UniAST::RightValue::setmlirValue(mlir::Value value)
{
    this->mlirValue = value;
}

mlir::Value UniAST::RightValue::getmlirValue()
{
    return this->mlirValue;
}

void UniAST::RightValue::setType(std::shared_ptr<UniAST::Type> exprtype)
{
    this->exprtype = exprtype;
}

std::shared_ptr<UniAST::Type> UniAST::RightValue::getType()
{
    return this->exprtype;
}

UniAST::Expression::Expression(
    OPERATOR op, std::vector<std::shared_ptr<RightValue>> exprParams,
    std::shared_ptr<UniAST::Type> exprtype, mlir::Value mlirvalue)
    : RightValue(exprtype, mlirvalue), exprParams(exprParams), op(op)
{
}

std::shared_ptr<UniAST::Type>
inferExprType(UniAST::Expression::OPERATOR op,
              std::vector<std::shared_ptr<UniAST::RightValue>> params)
{
    if (op == UniAST::Expression::OPERATOR::ADD ||
        op == UniAST::Expression::OPERATOR::SUB)
    {
        auto lhsty = params[0]->getType();
        auto rhsty = params[1]->getType();
        if (lhsty->isFloatType() || rhsty->isFloatType())
        {
            return UniAST::FloatType::get(32);
        }
        else
        {
            return UniAST::IntegerType::get(32);
        }
    }
    else
    {
        assert(false && "unsupport op");
    }
}

std::shared_ptr<UniAST::Expression> UniAST::Expression::get(
    std::vector<std::shared_ptr<UniAST::RightValue>> params, OPERATOR op,
    mlir::Value mlirvalue)
{
    return std::make_shared<Expression>(
        op, params, inferExprType(op, params), mlirvalue);
}

UniAST::PrimaryExpression::PrimaryExpression(
    std::shared_ptr<UniAST::Type> exprtype, mlir::Value mlirValue)
    : RightValue(exprtype, mlirValue)
{
}

UniAST::VariableAccess::VariableAccess(
    std::shared_ptr<UniAST::Variable> var,
    std::shared_ptr<UniAST::Type> exprtype, mlir::Value mlirValue)
    : PrimaryExpression(exprtype, mlirValue), var(var)
{
}

std::shared_ptr<UniAST::VariableAccess>
UniAST::VariableAccess::get(std::shared_ptr<UniAST::Variable> var,
                            mlir::Value mlirValue)
{
    return std::make_shared<UniAST::VariableAccess>(var, var->getType(),
                                                    mlirValue);
}

UniAST::Literal::Literal(std::shared_ptr<UniAST::Type> exprtype,
                         mlir::Value mlirValue)
    : PrimaryExpression(exprtype, mlirValue)
{
}

UniAST::IntergerLiteral::IntergerLiteral(long int content,
                                         mlir::Value mlirValue)
    : Literal(UniAST::IntegerType::get(32), mlirValue), content(content)
{
}

std::shared_ptr<UniAST::IntergerLiteral>
UniAST::IntergerLiteral::get(long int content, mlir::Value mlirValue)
{
    return std::make_shared<UniAST::IntergerLiteral>(content, mlirValue);
}